﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Threading;
using System.Diagnostics;
using ESF.General;
using ESF.General.Bulk;

#endregion


namespace ESF.Bulk
{
	public class WorkerQueue
	{
		#region Delegados
		
		public delegate bool GetTask (out ITask pTask, int pWorkerIndex);
		public delegate void TaskConfirmed (int pAverageTimeDurationMs, int pWorkerIndex);
		public delegate void TreatException (Exception pEx, int pTryCount);
		
		#endregion
		
		
		#region Constantes
		
		private const int DEFAULT_WAITMS = 100;
		
		#endregion
	
	
		#region Miembros
		
		private Thread _Thread;
		
		private GetTask _DelGetTask;
		
		private TaskConfirmed _DelTaskConfirmed;
		
		private TreatException _DelTreatException;
		
		private int _MaxTryCount;
		private int _Index;
		private int _AverageTaskDurationMs;
		
		private string _Lock;
		
		private bool _Active;
		private bool _Stopped;
		
		private Stopwatch _Stopwatch;
		
		#endregion
		
		
		#region Propiedades
		
		public bool Active
		{
			get { return _Active; }
		}
		
		
		public bool Stopped
		{
			get { return _Stopped; }
		}
		
		
		public int Index
		{
			get { return _Index; }
		}
		
		#endregion
	
	
		#region Constructor
		
		private WorkerQueue () {}
		
		
		public WorkerQueue (GetTask pdelGetTask, TaskConfirmed pdelTaskConfirmed, TreatException pdelTreatException, int pMaxTryCount, int pIndex)
		{
			_DelGetTask = pdelGetTask;
			
			_DelTaskConfirmed = pdelTaskConfirmed;
			
			_DelTreatException = pdelTreatException;
		
			_MaxTryCount = pMaxTryCount;
			
			_AverageTaskDurationMs = DEFAULT_WAITMS;
			
			_Index = pIndex;
			
			_Stopwatch = new Stopwatch ();
			
			_Lock = string.Empty;
			
			_Stopped = true;
			
			Stop ();
		}
		
		#endregion
		
	
		#region Funciones
		
		public void Stop ()
		{
			_Active = false;
			
			//Console.WriteLine ("Stopped {0}", _Index);
		}
		
		
		public void Start ()
		{
			//lock (_Lock)
			//{
				if (_Active) { return; }
				// Console.WriteLine ("Started {0}", _Index);
			
				_Active = true;
				_Stopped = false;
				
				if (_Thread == null)
				{
					_Thread = new Thread (new ThreadStart (Do));
					_Thread.Start ();
				}
			//}
		}
		
		
		private void Do ()
		{
			ITask task = null;
			
			while (_Active)
			{
				if (!_DelGetTask (out task, _Index))
				{
					Thread.Sleep (DEFAULT_WAITMS);
					continue;
				}
			
				for (int i = 1; i <= _MaxTryCount; i++)
				{
					_Stopwatch.Reset ();

					try
					{
						_Stopwatch.Start ();
					
						task.Do ();
						task.Confirm ();
					
						_Stopwatch.Stop ();
					
						_AverageTaskDurationMs = (int) (_AverageTaskDurationMs + _Stopwatch.ElapsedMilliseconds) / 2;
						
						_DelTaskConfirmed (_AverageTaskDurationMs, _Index);
						
						break;
					}
					catch (Exception pEx)
					{
						_Stopwatch.Stop ();
						
						_DelTreatException (pEx, i);
						
						Thread.Sleep ((int) _Stopwatch.ElapsedMilliseconds);
					}
				}
			}
			
			lock (_Lock) { _Stopped = true; }
		}
		
		#endregion
	}
}
